#include "stdafx.h"

#include <MyControls/DrawTool.h>
#include <MyControls/BezierManip.h>
#include <MyControls/BezierEditor.h>

namespace My {

DrawTool::DrawTool(BezierEditor & owner) : 
	m_Owner(owner),
	m_Convert(owner),
	m_AddPoint(owner)
{
	m_Mode = tmDraw;
}

void DrawTool::PaintRect(CDC * pDC, const CRect &)
{
}

void DrawTool::OnLButtonDown(UINT nFlags, CPoint p)
{
	Size dir;
	Bezier * pCurve = GetActiveCurve(dir);
	if (pCurve != 0) 
	{
		CRect r(p, p);
		r.InflateRect(m_Owner.GetTolerance(), m_Owner.GetTolerance());
		rect<float> fr = m_Owner.GetBench().ClientToBench(r);
		Size index = (dir == 1 ? 0 : pCurve->GetNodeCount() - 1);
		if (fr.inside(pCurve->GetNode(index).position)) {
			// close the curve
			pCurve->Close();
			pCurve->Select();
			m_Owner.GetBench().Invalidate();
			m_Mode = tmDraw;
			return;
		}
	}
	Size icurve, inode, icontrol;
	if (m_Owner.ControlPointAt(p, icurve, inode, icontrol)
		|| m_Owner.NodeAt(p, icurve, inode)) {
			m_Convert.OnLButtonDown(nFlags, p);
			m_Mode = tmConvert;
			return;
		}
	float t;
	if (m_Owner.CurveAt(p, icurve, t)) {
		m_AddPoint.OnLButtonDown(nFlags, p);
		m_Mode = tmAddPoint;
		return;
	}
	if (pCurve != 0)
		m_Owner.GetBench().SetManipulator(
			std::auto_ptr<Manipulator>(new DrawNextPoint(
				m_Owner,
				* pCurve,
				dir,
				p)));
	else
		m_Owner.GetBench().SetManipulator(
			std::auto_ptr<Manipulator>(new DrawFirstPoint(
				m_Owner,
				p)));
	m_Mode = tmDraw;
}

void DrawTool::OnLButtonDblClk(UINT nFlags, CPoint p)
{
}

void DrawTool::OnLButtonUp(UINT nFlags, CPoint p)
{
	switch (m_Mode) {
		case tmDraw:
			break;
		case tmConvert:
			m_Convert.OnLButtonUp(nFlags, p);
			break;
		case tmAddPoint:
			m_AddPoint.OnLButtonUp(nFlags, p);
			break;
	}
	m_Mode = tmDraw;
}

void DrawTool::OnRButtonDown(UINT nFlags, CPoint p)
{
}

void DrawTool::OnRButtonDblClk(UINT nFlags, CPoint p)
{
}

void DrawTool::OnRButtonUp(UINT nFlags, CPoint p)
{
}

void DrawTool::OnMouseMove(UINT nFlags, CPoint p)
{
	switch (m_Mode) {
		case tmDraw:
			break;
		case tmConvert:
			m_Convert.OnMouseMove(nFlags, p);
			break;
		case tmAddPoint:
			m_AddPoint.OnMouseMove(nFlags, p);
			break;
	}
}

void DrawTool::OnMouseEnter(UINT nFlags, CPoint p)
{
}

void DrawTool::OnMouseLeave()
{
}

void DrawTool::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
}

void DrawTool::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
}

bool DrawTool::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
	CPoint p;
	GetCursorPos(&p);
	m_Owner.GetBench().ScreenToClient(&p);

	Size dir;
	Bezier * pCurve = GetActiveCurve(dir);
	if (pCurve != 0) 
	{
		CRect r(p, p);
		r.InflateRect(m_Owner.GetTolerance(), m_Owner.GetTolerance());
		rect<float> fr = m_Owner.GetBench().ClientToBench(r);
		Size index = (dir == 1 ? 0 : pCurve->GetNodeCount() - 1);
		if (fr.inside(pCurve->GetNode(index).position)) {
			SetCursor(GetApp().LoadCursor("CURSOR_PEN_CLOSE"));
			return true;
		}
	}

	Size icurve, inode, icontrol;
	if (m_Owner.ControlPointAt(p, icurve, inode, icontrol) 
		|| m_Owner.NodeAt(p, icurve, inode)) 
	{
		SetCursor(GetApp().LoadCursor("CURSOR_CONVERT"));
		return true;
	}
	float t;
	if (m_Owner.CurveAt(p, icurve, t)) {
		SetCursor(GetApp().LoadCursor("CURSOR_PEN_ADD"));
		return true;
	}

	SetCursor(GetApp().LoadCursor("CURSOR_PEN"));
	return true;
}

Bezier * DrawTool::GetActiveCurve(Size & dir) const
{
	Bezier * pCurve = 0;
	Size count = 0;
	for (Size i = 0; i < m_Owner.GetBezierOwner()->GetBezierCount(); ++i) {
		Bezier & b = m_Owner.GetBezierOwner()->GetBezier(i);
		for (Size j = 0; j < b.GetNodeCount(); ++j)
			if (b.IsSelected(j)) {
				++count;
				pCurve = &b;
			}
	}
	if (count != 1 || pCurve->IsClosed())
		return 0;
	if (pCurve->IsSelected(pCurve->GetNodeCount() - 1)) {
		dir = 1;
	} else if (pCurve->IsSelected(0)) {
		dir = 0;
	} else
		pCurve = 0;
	return pCurve;
}

} //namespace My
